import constants from '@/constants';
import { BaseService } from '@/core/base.service';
import { AdminQueryDto } from '@/dtos';
import { getHash } from '@/utils';
import { Injectable } from '@nestjs/common';
import { Admin, Prisma } from '@prisma/client';

@Injectable()
export class AdminService extends BaseService {
  async query({ params, sort }: AdminQueryDto) {
    const {
      current = 1,
      pageSize = 20,
      keyword,
      dateTimeRange,
      ...where
    } = params;

    let sql = `
      SELECT #{fields} FROM Admin AS t
      LEFT JOIN Role AS r ON t.roleId = r.id
      WHERE t.isDeleted = false
        ${where.account ? `AND t.account LIKE '%${where.account}%'` : ''}
        ${where.mobile ? `AND t.mobile LIKE '%${where.mobile}%'` : ''}
        ${where.realname ? `AND t.realname LIKE '%${where.realname}%'` : ''}
        ${where.roleId ? `AND t.roleId = ${where.roleId}` : ''}
    `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(t.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<Admin[]>(
      `${sql.replace(
        '#{fields}',
        `
          t.id, t.account, t.mobile, t.realname, t.avatar, t.isSuperAdmin, t.isEnabled, t.createdAt,
          t.roleId, r.name AS role, r.desc
        `,
      )}
      ORDER BY ${
        !!sort && Object.keys(sort).length > 0
          ? Object.entries(sort)
              .map(([k, v]) => {
                if (k === 'hold') {
                  return `${k} ${v === 'descend' ? 'DESC' : 'ASC'}`;
                }
                return `t.${k} ${v === 'descend' ? 'DESC' : 'ASC'}`;
              })
              .join(',')
          : 't.createdAt DESC'
      }
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize}
      `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list,
    };
  }

  async findOne(
    where: Prisma.AdminWhereUniqueInput,
    select?: Prisma.AdminSelect,
  ): Promise<Admin | null> {
    return this.prisma.admin.findUnique({
      where,
      select,
    });
  }

  async create(data: Prisma.AdminCreateInput): Promise<Admin> {
    return this.prisma.admin.create({
      data: {
        ...data,
        pass: await getHash(data.pass ?? constants.default.pass),
      },
    });
  }

  async update(params: {
    where: Prisma.AdminWhereUniqueInput;
    data: Prisma.AdminUpdateInput;
  }): Promise<Admin> {
    const { where, data } = params;
    return this.prisma.admin.update({
      where,
      data: {
        ...data,
        ...(!!data.pass ? { pass: await getHash(data.pass as string) } : {}),
      },
    });
  }

  async remove(where: Prisma.AdminWhereUniqueInput): Promise<Admin> {
    return this.prisma.admin.update({
      where,
      data: {
        isDeleted: true,
      },
    });
  }
}
